#include "ImageDisplay.h"

ImageDisplay::ImageDisplay(wxWindow* parent) :
    wxPanel(parent,wxID_ANY)
{
    currentImage.Create(10,10);
    Bind(wxEVT_PAINT,&ImageDisplay::OnPaint,this,wxID_ANY);
}

ImageDisplay::~ImageDisplay()
{
}

void ImageDisplay::doImageSet(long _width,long _height)
{
    //HandleAreaX=_width;
    //HandleAreaY=_height;
    displayRawImage=true;
    displayFilterImage=false;
    Refresh(true);
}

void ImageDisplay::SetImage(unsigned char* _imageData,long _height,long _width)
{
    currentImage.SetData(_imageData,_width,_height,false);
    doImageSet(_width,_height);
}

void ImageDisplay::SetImage(wxImage& image)
{
    currentImage=image;
    doImageSet(image.GetWidth(),image.GetHeight());
}

void ImageDisplay::OnPaint(wxPaintEvent& event)
{
    wxSize size=GetClientSize();
    wxPaintDC dc(this);
    dc.Clear();
    //dc.DrawBitmap(currentImage.Scale(size.x,size.y),0,0,false);
    if(displayRawImage)
        dc.DrawBitmap(currentImage,0,0,false);
    if(displayFilterImage)
        dc.DrawBitmap(fliterResImage,0,0,false);
    if(displayPosInf)
        //DrawPos(SaclePos(MarkPos),dc);
        DrawPos(MarkPos,dc);
    if(displayHandleArea)
        DrawHandleArea(dc);
    if(displayPointLinks)
        DrawLinkPoints(dc);
    
}

void ImageDisplay::SetHandleArea(long xx,long yy)
{
    HandleAreaX=xx;
    HandleAreaY=yy;
    displayHandleArea=true;
    Refresh(true);
}

void ImageDisplay::DrawHandleArea(wxPaintDC& dc)
{
    wxPen pen;
    pen.SetWidth(2);
    pen.SetColour(0,255,0);
    dc.SetPen(pen);
    dc.DrawLine(0,0,HandleAreaX,0);
    dc.DrawLine(0,0,0,HandleAreaY);
    dc.DrawLine(HandleAreaX,0,HandleAreaX,HandleAreaY);
    dc.DrawLine(0,HandleAreaY,HandleAreaX,HandleAreaY);
}

unsigned char* ImgRGBtoGray(const unsigned char* RGBdata,int imageHeight,int imageWidth)
{
    unsigned char* res=new unsigned char[imageHeight*imageWidth];
    for(int i=0;i<imageHeight*imageWidth;i++)
    {
        //res[i]=(RGBdata[i*3]*19595+RGBdata[i*3+1]*38469+RGBdata[i*3+2]*7472)>>16;
        res[i]=RGBdata[i*3];
    }
    return res;
}

long ImageDisplay::PixelValue(int pixelValue,int Threshold)
{
    if(pixelValue>=Threshold)
        return pixelValue;
    else
        return 0;
}

long ImageDisplay::calSumValue(std::function<long(int,int)> func)
{
    long sum=0;
    for(int i=0;i<HandleAreaY;i++)
    {
        for(int j=0;j<HandleAreaX;j++)
        {
            sum+=func(i,j);
        }
    }
    return sum;
}

wxPoint ImageDisplay::grayCenter(int Threshold)
{
    wxPoint cPoint;
    size_t imageSize=currentImage.GetHeight()*currentImage.GetWidth();
    unsigned char* imageData=ImgRGBtoGray(currentImage.GetData(),currentImage.GetHeight(),currentImage.GetWidth());
    unsigned char* cImageData=RouteImage(imageData,imageSize);
    ReversalColor(cImageData,currentImage.GetHeight()*currentImage.GetWidth());
    long divV=calSumValue([&](int x,int y){return PixelValue(cImageData[y*currentImage.GetWidth()+x],Threshold);});
    if(divV<=0)
    {
        wxMessageBox(wxT("图像没有有效数据或数据为空"),wxT("处理错误"));
        delete [] imageData;
        delete [] cImageData;
        return MarkPos;
    }
    cPoint.x=calSumValue([&](int x,int y){return x*PixelValue(cImageData[y*currentImage.GetWidth()+x],Threshold);}) / divV;
    cPoint.y=calSumValue([&](int x,int y){return y*PixelValue(cImageData[y*currentImage.GetWidth()+x],Threshold);}) / divV;
    delete [] imageData;
    delete [] cImageData;
    return cPoint;
}

wxPoint ImageDisplay::GetGrayCenter(unsigned char* _imageData,int Threshold)
{
    wxPoint cPoint;
    size_t imageSize=currentImage.GetHeight()*currentImage.GetWidth();
    unsigned char* cImageData=RouteImage(_imageData,imageSize);
    ReversalColor(cImageData,imageSize);
    long divV=calSumValue([&](int x,int y){return PixelValue(cImageData[y*currentImage.GetWidth()+x],Threshold);});
    if(divV<=0)
    {
        delete [] cImageData;
        throw (int)1;
    }
    cPoint.y=calSumValue([&](int x,int y){return x*PixelValue(cImageData[y*currentImage.GetWidth()+x],Threshold);}) / divV;
    cPoint.x=calSumValue([&](int x,int y){return y*PixelValue(cImageData[y*currentImage.GetWidth()+x],Threshold);}) / divV;
    delete [] cImageData;
    return cPoint;
}

void ImageDisplay::DrawPos(wxPoint pos,wxPaintDC& dc)
{
    wxPen pen;
    pen.SetColour(255,0,0);
    pen.SetWidth(3);
    dc.SetPen(pen);
    dc.DrawLine(pos.x-5,pos.y,pos.x+5,pos.y);
    dc.DrawLine(pos.x,pos.y-5,pos.x,pos.y+5);
}

void ImageDisplay::HandleImage(int Threshold)
{
    displayPosInf=true;
    displayPointLinks=false;
    wxPoint cp=grayCenter(Threshold);
    Refresh();
}

double CalScalePara(double value1,double value2)
{
    return value1/value2;
}

wxPoint ImageDisplay::SaclePos(wxPoint pos)
{
    wxPoint newPoint;
    newPoint.x=pos.x/CalScalePara(currentImage.GetWidth(),GetClientSize().GetWidth());
    newPoint.y=pos.y/CalScalePara(currentImage.GetHeight(),GetClientSize().GetHeight());
    return newPoint;
}

void ImageDisplay::ReversalColor(unsigned char* imageData,size_t size)
{
    for(int i=0;i<size;i++)
    {
        imageData[i]=0xFF-imageData[i];
    }
}

unsigned char* ImageDisplay::RouteImage(unsigned char* imageData,size_t size)
{
    unsigned char* resData=new unsigned char[size];
    long resPtr=0;
    for(int i=0;i<currentImage.GetHeight();i++)
    {
        for(int j=0;j<currentImage.GetWidth();j++)
        {
            resData[resPtr]=imageData[j*currentImage.GetHeight()+i];
            resPtr++;
        }
    }
    return resData;
}

void ImageDisplay::FilterImage(int Threshold)
{
    displayFilterImage=true;
    displayRawImage=false;
    displayPointLinks=false;
    const unsigned char* raw=currentImage.GetData();
    size_t imageSize=currentImage.GetHeight()*currentImage.GetWidth()*3;
    unsigned char* res=(unsigned char*)malloc(imageSize);
    std::memcpy(res,raw,imageSize);
    ReversalColor(res,imageSize);
    for(int i=0;i<imageSize;i++)
    {
        res[i]=PixelValue(res[i],Threshold);
    }
    fliterResImage.SetData(res,currentImage.GetWidth(),currentImage.GetHeight(),false);
    Refresh(true);
}

wxPoint ImageDisplay::GetTargetPos()
{
    return MarkPos;
}

void ImageDisplay::LinkPoints(wxPointList& pList)
{
    pointList=pList;
    displayPointLinks=true;
    Refresh(true);
}

void ImageDisplay::DrawLinkPoints(wxPaintDC& dc)
{
    wxPen pen;
    pen.SetColour(0,0,255);
    pen.SetWidth(2);
    dc.SetPen(pen);
    dc.DrawSpline(&pointList);
}